package com.example.system.service.impl;

import cn.hutool.json.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.common.config.AlipayConfig;
import com.example.common.enums.CodeEnum;
import com.example.common.exception.ServiceException;
import com.example.common.utils.R;
import com.example.system.dto.PaymentDTO;
import com.example.system.entity.*;
import com.example.system.mapper.OrderMapper;
import com.example.system.mapper.PatientMapper;
import com.example.system.mapper.PaymentMapper;
import com.example.system.mapper.UserMapper;
import com.example.system.service.IPatientService;
import com.example.system.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 王鹤蒲
 * @since 2024-01-22
 */
@Service
@Slf4j
public class PatientServiceImpl extends ServiceImpl<PatientMapper, Patient> implements IPatientService {

    @Autowired
    private PatientMapper patientMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private PaymentMapper paymentMapper;

    @Autowired
    private IUserService iUserService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AlipayConfig alipayConfig;

    private static final String GATEWAY_URL = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";

    private static final String FORMAT = "JSON";

    private static final String CHARSET = "utf-8";

    private static final String SIGN_TYPE = "RSA2";

    @Override
    public R insert(Patient patient) {
        LocalDateTime createTime = LocalDateTime.now();
        User user = patient.getUser();
        String encryptedPassword = passwordEncoder.encode(user.getPassword());
        user.setPassword(encryptedPassword);
        user.setCreateTime(createTime);
        user.setCreateBy(iUserService.getCurrentLoginUser().getUserName());
        user.setRole("ROLE_PATIENT");
        user.setAvatar("http://localhost:8089/file/0df5e1114946486d9879afa0e8c6cff7.jpg");
        userMapper.insert(user);
        Integer userId = user.getUserId();
        patient.setUserId(userId).setCreateBy(iUserService.getCurrentLoginUser().getUserName()).setCreateTime(createTime);
        if (!patient.getIdNumber().isEmpty()) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            LocalDate birthDate = LocalDate.parse(patient.getIdNumber().substring(6, 10) + "-" + patient.getIdNumber().substring(10, 12) + "-" + patient.getIdNumber().substring(12, 14), formatter);
            patient.setBirthDate(birthDate);
        }
        patientMapper.insert(patient);
        return R.success();
    }


    @Override
    public R pay(PaymentDTO paymentDTO) {
        AlipayClient client = new DefaultAlipayClient(GATEWAY_URL, alipayConfig.getAppId(), alipayConfig.getAppPrivateKey(), FORMAT, CHARSET, alipayConfig.getAlipayPublicKey(), SIGN_TYPE);
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setNotifyUrl(alipayConfig.getNotifyUrl());
        request.setReturnUrl(alipayConfig.getReturnUrl());
        JSONObject bizContent = new JSONObject();
        bizContent.set("out_trade_no", paymentDTO.getOrderNo());
        bizContent.set("total_amount", paymentDTO.getAmount());
        bizContent.set("subject", paymentDTO.getSubject());
        bizContent.set("product_code", "FAST_INSTANT_TRADE_PAY");
        request.setBizContent(bizContent.toString());
        String form = "";
        try {
            form = client.pageExecute(request).getBody();
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }
        return R.success(form);
    }

    @Override
    public String payNotify(HttpServletRequest request) throws AlipayApiException {
        LocalDateTime currentTime = LocalDateTime.now();
        Payment payment = new Payment();
        payment.setOrderNo(request.getParameter("out_trade_no")).setTradeNo(request.getParameter("trade_no")).setAmount(Double.valueOf(request.getParameter("total_amount"))).setBuyerId(request.getParameter("buyer_id")).setPaymentMethod("0");
        if ("TRADE_SUCCESS".equals(request.getParameter("trade_status"))) {
            Map<String, String> params = new HashMap();
            Enumeration<String> enumeration = request.getParameterNames();
            String name = null;
            while (enumeration.hasMoreElements()) {
                name = enumeration.nextElement();
                params.put(name, request.getParameter(name));
            }
            String outTradeNo = params.get("out_trade_no");
            String gmtPayment = params.get("gmt_payment");
            String tradeNo = params.get("trade_no");
            String sign = params.get("sign");
            String content = AlipaySignature.getSignCheckContentV1(params);
            Boolean checkSignature = AlipaySignature.rsa256CheckContent(content, sign, alipayConfig.getAlipayPublicKey(), "UTF-8");
            if (checkSignature) {
                log.info("订单号：{}", params.get("out_trade_no"));
                log.info("交易名称：{}", params.get("subject"));
                log.info("交易状态：{}", params.get("trade_status"));
                log.info("交易金额：{}", params.get("total_amount"));
                log.info("支付宝交易凭证号：{}", params.get("trade_no"));
                log.info("买家在支付宝唯一id：{}", params.get("buyer_id"));
                log.info("买家付款金额：{}", params.get("buyer_pay_amount"));
                log.info("买家付款时间：{}", params.get("gmt_payment"));
                payment.setStatus("1");
                LambdaUpdateWrapper<Order> orderLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                orderLambdaUpdateWrapper.eq(Order::getOrderNo, outTradeNo);
                orderLambdaUpdateWrapper.set(Order::getStatus, "1");
                orderMapper.update(new Order(), orderLambdaUpdateWrapper);
                LambdaQueryWrapper<Order> orderLambdaQueryWrapper = new LambdaQueryWrapper<>();
                orderLambdaQueryWrapper.eq(Order::getOrderNo, outTradeNo);
                Integer patientId = orderMapper.selectOne(orderLambdaQueryWrapper).getPatientId();
                LambdaUpdateWrapper<Patient> patientLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                patientLambdaUpdateWrapper.eq(Patient::getId, patientId);
                patientLambdaUpdateWrapper.setSql("account=account+" + Double.valueOf(params.get("total_amount")));
                patientMapper.update(new Patient(), patientLambdaUpdateWrapper);
            }
        } else {
            payment.setStatus("0");
            paymentMapper.insert(payment);
            return "failure";
        }
        paymentMapper.insert(payment);
        return "success";
    }


    @Override
    public R selectAll(int currentPage, int pageSize, String patientName) {
        Page<Patient> page = new Page<>(currentPage, pageSize);
        return R.success(patientMapper.findByPage(page, patientName));
    }

    @Override
    public R deleteById(int id) {
        LocalDateTime deleteTime = LocalDateTime.now();
        LambdaQueryWrapper<Patient> patientLambdaQueryWrapper = new LambdaQueryWrapper<>();
        patientLambdaQueryWrapper.eq(Patient::getId, id);
        Integer userId = patientMapper.selectOne(patientLambdaQueryWrapper).getUserId();
        LambdaUpdateWrapper<User> userLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        userLambdaUpdateWrapper.eq(User::getUserId, userId);
        userLambdaUpdateWrapper.set(User::getStatus, "0");
        userLambdaUpdateWrapper.set(User::getDelFlag, "1");
        userLambdaUpdateWrapper.set(User::getUpdateBy, iUserService.getCurrentLoginUser().getUserName());
        userLambdaUpdateWrapper.set(User::getUpdateTime, deleteTime);
        userMapper.update(new User(), userLambdaUpdateWrapper);
        return R.success();
    }

    @Override
    public R deleteByIds(int[] ids) {
        LocalDateTime deleteTime = LocalDateTime.now();
        LambdaQueryWrapper<Patient> patientLambdaQueryWrapper = new LambdaQueryWrapper<>();
        LambdaUpdateWrapper<User> userLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        Integer userId = null;
        for (Integer id : ids) {
            patientLambdaQueryWrapper.eq(Patient::getId, id);
            userId = patientMapper.selectOne(patientLambdaQueryWrapper).getUserId();
            userLambdaUpdateWrapper.eq(User::getUserId, userId);
            userLambdaUpdateWrapper.set(User::getStatus, "0");
            userLambdaUpdateWrapper.set(User::getDelFlag, "1");
            userLambdaUpdateWrapper.set(User::getUpdateBy, iUserService.getCurrentLoginUser().getUserName());
            userLambdaUpdateWrapper.set(User::getUpdateTime, deleteTime);
            userMapper.update(new User(), userLambdaUpdateWrapper);
            userLambdaUpdateWrapper.clear();
            patientLambdaQueryWrapper.clear();
        }
        return R.success();
    }

    @Override
    public R edit(Patient patient) {
        System.out.println(patient);
        LocalDateTime updateTime = LocalDateTime.now();
        LambdaUpdateWrapper<User> userLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        userLambdaUpdateWrapper.eq(User::getUserId, patient.getUserId());
        User user = patient.getUser();
        user.setUpdateBy(iUserService.getCurrentLoginUser().getUserName());
        user.setUpdateTime(updateTime);
        userMapper.update(user, userLambdaUpdateWrapper);
        if (!patient.getIdNumber().isEmpty()) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            LocalDate birthDate = LocalDate.parse(patient.getIdNumber().substring(6, 10) + "-" + patient.getIdNumber().substring(10, 12) + "-" + patient.getIdNumber().substring(12, 14), formatter);
            patient.setBirthDate(birthDate);
        }
        patientMapper.updateById(patient);
        return R.success();
    }
}
